package com.hzmg.worker.autoconfigure;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.hzmg.akkacloud.common.utils.CommonUtils;
import com.hzmg.akkacloud.common.utils.NetUtils;
import com.hzmg.akkacloud.worker.AkkaCloudWorker;
import com.hzmg.akkacloud.worker.common.AkkaCloudWorkerConfig;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * Auto configuration class for AkkaCloud-worker.
 *
 * @author zbw
 * @since 2022/7/9
 */
@Configuration
@EnableConfigurationProperties(AkkaCloudProperties.class)
@Conditional(AkkaCloudAutoConfiguration.AkkaCloudWorkerCondition.class)
public class AkkaCloudAutoConfiguration {

    @Bean
    //保证bean只有一个的注解
    @ConditionalOnMissingBean
    public AkkaCloudWorker initAkkaCloud(AkkaCloudProperties properties) {

        AkkaCloudProperties.Worker worker = properties.getWorker();

        /*
         * Address of AkkaCloud-server node(s). Do not mistake for ActorSystem port.
         * Do not add any prefix, i.e. http://.
         */
        CommonUtils.requireNonNull(worker.getServerAddress(), "serverAddress can't be empty!");
        List<String> serverAddress = Arrays.asList(worker.getServerAddress().split(","));

        /*
         * Create AkkaCloudConfig object for setting properties.
         */
        AkkaCloudWorkerConfig config = new AkkaCloudWorkerConfig();
        /*
         * Configuration of worker port. Random port is enabled when port is set with non-positive  number.
         */
        int port = worker.getAkkaPort();
        if (port <= 0) {
            port = NetUtils.getRandomPort();
        }
        config.setPort(port);
        /*
         * appName, name of the application. Applications should be registered in advance to prevent
         * error. This property should be the same with what you entered for appName when getting
         * registered.
         */
        config.setAppName(worker.getAppName());
        config.setServerAddress(serverAddress);
        List<String> userRoles = Arrays.asList(worker.getUserRole().split(","));
        config.setUserRoles(userRoles);
        /*
         * For non-Map/MapReduce tasks, {@code memory} is recommended for speeding up calculation.
         * Map/MapReduce tasks may produce batches of subtasks, which could lead to OutOfMemory
         * exception or error, {@code disk} should be applied.
         */
        config.setStoreStrategy(worker.getStoreStrategy());
        /*
         * When enabledTestMode is set as true, AkkaCloud-worker no longer connects to AkkaCloud-server
         * or validate appName.
         */
        config.setEnableTestMode(worker.isEnableTestMode());
        /*
         * Max length of appended workflow context . Appended workflow context value that is longer than the value will be ignore.
         */
        config.setMaxAppendedWfContextLength(worker.getMaxAppendedWfContextLength());
        /*
         * Create AkkaCloudWorker object and set properties.
         */
        AkkaCloudWorker cloudWorker = new AkkaCloudWorker();
        cloudWorker.setConfig(config);
        return cloudWorker;
    }
    /**
     * 只要match任意condition,目标实例就会被注册
     */
    static class AkkaCloudWorkerCondition extends AnyNestedCondition {

        public AkkaCloudWorkerCondition() {
            super(ConfigurationPhase.PARSE_CONFIGURATION);
        }

        @ConditionalOnProperty(prefix = "akkacloud.worker", name = "server-address")
        static class AkkaCloudWorkerProperty {

        }
    }
/*    @Component
    public class StringTrimModule extends SimpleModule {

        public StringTrimModule() {
            addDeserializer(String.class, new StdScalarDeserializer<String>(String.class) {
                @Override
                public String deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
                    String value = jsonParser.getValueAsString();
                    if (StringUtils.isEmpty(value)) {
                        return value;
                    }
                    return value.trim();
                }
            });
        }
    }*/
}
